/*
* $Id: ComboBoxDraw.cpp 112 2010-07-07 15:15:39Z volok-aleksej@yandex.ru $
*
* Copyright 2009 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "ComboBoxDraw.h"
#include "KeyProcess.h"

CComboBoxDraw::CComboBoxDraw(const std::tstring& strName, CEditorItem* pParent)
: CDrawControl(strName), m_pParent(pParent), m_bPushUpScroll(false),
m_bPushDownScroll(false), m_nLines(6), m_nSel(0), m_nFirstVisibleItem(0), m_bScroll(false){
	m_aKeyProcess.push_back(new CArrawUp(this));
	m_aKeyProcess.push_back(new CArrawDown(this));
}
CComboBoxDraw::~CComboBoxDraw(){}

void CComboBoxDraw::SetPos(CPoint pos){
	CPoint posRes = pos - m_rect.TopLeft();
	m_rect.MoveToXY(pos);
}

void CComboBoxDraw::AddItem(int nIdItem, std::tstring strValueItem){
	m_aItems.push_back(Item(nIdItem, strValueItem));
}

void CComboBoxDraw::Resize(){
	HDC dc = GetDC(GetDesktopWindow());
	CSize size_temp;
	GetTextExtentPoint32(dc, _T(" "), 1, &size_temp);
	if((int)m_aItems.size() < m_nLines)
		m_rect.bottom = m_rect.top + size_temp.cy * (int)m_aItems.size();
	else
		m_rect.bottom = m_rect.top + size_temp.cy * m_nLines;
	DeleteDC(dc);
}

void CComboBoxDraw::PaintActive(CDC* dc){
	CBrush brush;
	brush.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
	dc->FillRect(m_rect, &brush);
	brush.DeleteObject();
	PaintControl(dc);
}

void CComboBoxDraw::PaintNonActive(CDC* dc){
	CBrush brush;
	brush.CreateSolidBrush(GetSysColor(COLOR_3DFACE));
	dc->FillRect(m_rect, &brush);
	brush.DeleteObject();
	PaintControl(dc);
}

void CComboBoxDraw::PaintControl(CDC* dc){
	if(m_nFirstVisibleItem >= (int)m_aItems.size())
		return;
	dc->SetBkMode(TRANSPARENT);
	int nSizeLine = m_nLines;
	if((int)m_aItems.size() < m_nLines)
		nSizeLine = (int)m_aItems.size();
	for(int i = m_nFirstVisibleItem, n = 0; n < nSizeLine && i < (int)m_aItems.size(); i++, n++){
		CRect rect(m_rect.left, m_rect.top + m_rect.Size().cy/nSizeLine*n, m_rect.right, m_rect.top + m_rect.Size().cy/nSizeLine*(n + 1));
		if(m_nSel == i){
			CBrush brush;
			brush.CreateSolidBrush(RGB(0, 0, 255));
			dc->FillRect(rect, &brush);
			brush.DeleteObject();
			dc->SetTextColor(GetSysColor(COLOR_WINDOW));
		}else{
			dc->SetTextColor(RGB(0, 0, 0));
		}
		dc->DrawText(m_aItems[i].m_strValue.c_str(), rect, DT_LEFT);
	}
	dc->SetTextColor(RGB(0, 0, 0));

	if((int)m_aItems.size() > m_nLines){
		CBrush brush;
		brush.CreateSolidBrush(GetSysColor(COLOR_3DFACE));
		int cyLine = m_rect.Size().cy/m_nLines;
		dc->FillRect(CRect(m_rect.right - cyLine, m_rect.top, m_rect.right, m_rect.bottom), &brush);
		brush.DeleteObject();
		dc->DrawFrameControl(CRect(m_rect.right - cyLine, m_rect.top, m_rect.right, m_rect.top + cyLine),
							DFC_SCROLL, DFCS_SCROLLUP|(m_bPushUpScroll ? DFCS_PUSHED : 0));
		dc->DrawFrameControl(CRect(m_rect.right - cyLine, m_rect.bottom - cyLine, m_rect.right, m_rect.bottom),
							DFC_SCROLL, DFCS_SCROLLDOWN|(m_bPushDownScroll ? DFCS_PUSHED : 0));
		dc->DrawFrameControl(GetRectScrollButton(), DFC_BUTTON, DFCS_BUTTONPUSH);
	}
}

void CComboBoxDraw::OffsetSelection(int offset){
	if(m_nSel < (int)m_aItems.size()){
		if(offset > 0){
			m_nSel += offset;
			if(m_nSel >= (int)m_aItems.size())
				m_nSel = (int)m_aItems.size() - 1;
			if(m_nSel - m_nFirstVisibleItem > m_nLines - 1)
					m_nFirstVisibleItem = m_nSel - m_nLines + 1;
		}else if(offset < 0){
			m_nSel += offset;
			if(m_nSel < 0)
				m_nSel = 0;
			if(m_nSel - m_nFirstVisibleItem < 0)
				m_nFirstVisibleItem = m_nSel;
		}
	}
}

std::tstring CComboBoxDraw::GetValue(){
	return CConvertFunction::ConvertFromInt(m_aItems[m_nSel].m_nId);
}

void CComboBoxDraw::SetValue(int nId){
	int nPos = -1;
	for(std::vector<Item>::iterator it = m_aItems.begin(); it != m_aItems.end(); it++){
		if(it->m_nId == nId){
			nPos = int(it - m_aItems.begin());
			break;
		}
	}
	if(nPos == -1)
		return;
	OffsetSelection(nPos - m_nSel);
}

bool CComboBoxDraw::ProcessMouse(unsigned int nChar, CPoint pos, int param){
	if(nChar != WM_LBUTTONDOWN && nChar != WM_MOUSEWHEEL && nChar != WM_MOUSEMOVE)
		return false;
	if(!m_rect.PtInRect(pos) || !m_rect.PtInRect(pos) && nChar == WM_MOUSEWHEEL)
		return true;
	if(nChar == WM_MOUSEMOVE && param != MK_LBUTTON){
		m_bScroll = false;
		return true;
	}
	int nLines = m_nLines;
	if((int)m_aItems.size() < m_nLines)
		nLines = (int)m_aItems.size();
	int cyLines = m_rect.Size().cy/nLines;
	CRect temp;
	if(nChar == WM_MOUSEMOVE && m_bScroll)
		SetRectScrollButton(pos);
	else if(nChar == WM_MOUSEWHEEL){
		if(param > 0)
			m_nFirstVisibleItem--;
		else
			m_nFirstVisibleItem++;
		if(m_nFirstVisibleItem < 0)
			m_nFirstVisibleItem = 0;
		else if(m_nFirstVisibleItem > (int)m_aItems.size() - nLines)
			m_nFirstVisibleItem = (int)m_aItems.size() - nLines;
	}else if((int)m_aItems.size() > m_nLines && pos.x < m_rect.right && pos.x > m_rect.right - cyLines){
		if(pos.y < m_rect.bottom && pos.y > m_rect.bottom - cyLines){
				m_nFirstVisibleItem++;
		}else if(pos.y > m_rect.top && pos.y < m_rect.top + cyLines){
				m_nFirstVisibleItem--;
		}else if(!(temp = GetRectScrollButton()).PtInRect(pos) && nChar != WM_MOUSEMOVE){
			if(pos.y > temp.bottom)
				m_nFirstVisibleItem += m_nLines;
			else if(pos.y < temp.top)
				m_nFirstVisibleItem -= m_nLines;
		}else if(temp.PtInRect(pos) && nChar == WM_LBUTTONDOWN && !m_bScroll)
			m_bScroll = true;
		if(m_nFirstVisibleItem < 0)
			m_nFirstVisibleItem = 0;
		else if(m_nFirstVisibleItem > (int)m_aItems.size() - nLines)
			m_nFirstVisibleItem = (int)m_aItems.size() - nLines;
	}else{
		int nLine = (pos.y - m_rect.top)/cyLines;
		OffsetSelection(nLine - m_nSel + m_nFirstVisibleItem);
	}
	return true;
}

CRect CComboBoxDraw::GetRectScrollButton(){
	int cyLine = m_rect.Size().cy/m_nLines;
	double nScrollLine = double((m_nLines - 2) * cyLine)/double((int)m_aItems.size() - m_nLines + 1);
	double nScrollButton = nScrollLine;
	if(nScrollButton < 5){
		nScrollLine = double((m_nLines - 2) * cyLine - 3)/double((int)m_aItems.size() - m_nLines);
		nScrollButton = 5;
	}
	int ybegin = cyLine + int(m_nFirstVisibleItem * nScrollLine);
	int yend = cyLine + int((m_nFirstVisibleItem + 1)*nScrollLine);
	return CRect(m_rect.right - cyLine, m_rect.top + ybegin, m_rect.right, m_rect.top + ybegin + (int)nScrollButton);
}

void CComboBoxDraw::SetRectScrollButton(CPoint pos){
	int cyLine = m_rect.Size().cy/m_nLines;
	double nScrollLine = double((m_nLines - 2) * cyLine)/double((int)m_aItems.size() - m_nLines + 1);
	m_nFirstVisibleItem = int((pos.y - cyLine - m_rect.top)/nScrollLine);
	if(m_nFirstVisibleItem < 0)
		m_nFirstVisibleItem = 0;
	else if(m_nFirstVisibleItem > (int)m_aItems.size() - m_nLines)
		m_nFirstVisibleItem = (int)m_aItems.size() - m_nLines;
}

void CComboBoxDraw::Sort(){
	std::sort(m_aItems.begin(), m_aItems.end());
}

void CComboBoxDraw::InsertItem(int nPos, int nItemId, std::tstring strItemValue){
	m_aItems.insert(m_aItems.begin() + nPos, Item(nItemId, strItemValue));
}
